//-----------------------------------------------------------------------
// <copyright file="Miscellaneous.cs" company="Microsoft">
// This should contain the copyright text
// </copyright>
// <summary>This contains helper routines</summary>
// <author>Kimmo Forss</author>
//-----------------------------------------------------------------------

namespace SharePoint.ImportExport.Importer
{
    using System;
    using System.Collections;
    using System.IO;
    using System.Reflection;
    using System.Xml;
    using System.Xml.Schema;
    using SharePoint.ImportExport.Core;

    /// <summary>
    /// This is a helper class
    /// </summary>
    internal class Miscellaneous
    {
        /// <summary>
        /// This is the internal count of parser errors
        /// </summary>
        private static int xmlParseErrorCount = 0;

        /// <summary>
        /// Helper function for finding the internal name of a field
        /// </summary>
        /// <param name="listFields">This is an array of fields</param>
        /// <param name="fieldName">This is the name of the field</param>
        /// <returns>Internal name of field</returns>
        public static string GetInternalFieldName(ArrayList listFields, string fieldName)
        {
            int i = 0;
            string foundFieldName = string.Empty;
            if (null == listFields)
            {
                return fieldName;
            }

            for (i = listFields.Count - 1; i > 0; i--)
            {
                Microsoft.SharePoint.SPField field = (Microsoft.SharePoint.SPField)listFields[i];
                if (field.Title == fieldName || field.InternalName == fieldName)
                {
                    foundFieldName = field.InternalName;
                    break;
                }
            }

            return foundFieldName;
        }

        /// <summary>
        /// This method checks that the file conforms to the schema definition
        /// </summary>
        /// <param name="xmlFileName">Name of XML file to check</param>
        /// <param name="xsdFile">Name of XSD file to use</param>
        /// <returns>true if succeeded</returns>
        public static bool CheckXmlFile(string xmlFileName, string xsdFile)
        {
            if (!File.Exists(xmlFileName))
            {
                Logger.Log(ErrorLevel.Information, "Could not open the file: " + xmlFileName);
                return true;
            }

            xmlParseErrorCount = 0;
            Stream stream = null;
            XmlTextReader xmlSchemaRdr = null;

            Assembly thisAssembly = Assembly.GetExecutingAssembly();

            // get the specified xsd
            stream = thisAssembly.GetManifestResourceStream(xsdFile);
            using (xmlSchemaRdr = new XmlTextReader(stream))
            {
                XmlReaderSettings settings = new XmlReaderSettings();
                settings.ValidationType = ValidationType.Schema;
                settings.ValidationEventHandler += new ValidationEventHandler(ValidationHandler);
                settings.Schemas.Add(string.Empty, xmlSchemaRdr);
                using (XmlReader xmlReader = XmlReader.Create(xmlFileName, settings))
                {
                    ////Load the xml document using the XMLValidationReader
                    bool continueReading = true;
                    try
                    {
                        while (continueReading)
                        {
                            continueReading = xmlReader.Read();
                        }
                    }
                    catch (XmlSchemaException xmlSchemaEx)
                    {
                        Logger.Log(ErrorLevel.Error, "XML file does not conform to schema. Error: " + xmlSchemaEx.Message);
                        return false;
                    }
                    catch (XmlException xmlEx)
                    {
                        Logger.Log(ErrorLevel.Error, "XML file does not conform to schema. Error: " + xmlEx.Message);
                        return false;
                    }
                    finally
                    {
                        if (null != stream)
                        {
                            stream.Close();
                        }

                        if (null != xmlSchemaRdr)
                        {
                            xmlSchemaRdr.Close();
                        }

                        if (null != xmlReader)
                        {
                            xmlReader.Close();
                        }
                    }
                }

                if (xmlParseErrorCount > 0)
                {
                    return false;
                }
                else
                {
                    return true;
                }
            }
        }

        /// <summary>
        /// Helper function for removing characters not allowed in SharePoint. 
        /// </summary>
        /// <param name="stringToBeFixed">This is the field to be parsed for non supported characters</param>
        /// <returns>A string that SharePoint acceps</returns>
        public static string FixName(string stringToBeFixed)
        {
            string temporaryString = stringToBeFixed;
            char[] escapeChars = 
            {
                '?', 
                '=', 
                ':', 
                ';', 
                ']', 
                '[', 
                '/', 
                '\\', 
                '*', 
                '>', 
                '<', 
                '|', 
                '&', 
                '%', 
                '#', 
                '~' 
            };

            if (-1 != temporaryString.IndexOfAny(escapeChars))
            {
                temporaryString = temporaryString.Replace("?", "_");
                temporaryString = temporaryString.Replace("=", "_");
                temporaryString = temporaryString.Replace(":", "_");
                temporaryString = temporaryString.Replace("/", "_");
                temporaryString = temporaryString.Replace("\\", "_");
                temporaryString = temporaryString.Replace("*", "_");
                temporaryString = temporaryString.Replace(">", "_");
                temporaryString = temporaryString.Replace("<", "_");
                temporaryString = temporaryString.Replace("|", "_");

                //// The following are not valid in WSS
                //// Todo:  get a comprehensive list of bad characters for WSS.....add below.

                temporaryString = temporaryString.Replace("&", " And ");
                temporaryString = temporaryString.Replace("%", " PCT ");
                temporaryString = temporaryString.Replace("#", "_");
                temporaryString = temporaryString.Replace("~", "_");
                temporaryString = temporaryString.Replace("[", "_");
                temporaryString = temporaryString.Replace("]", "_");
                //////RPC fails if ; is in the string
                temporaryString = temporaryString.Replace(";", "_");
            }

            return temporaryString;
        }

        /// <summary>
        /// Validation handler logs validation errors(if any) and maintains the error count
        /// </summary>
        /// <param name="sender">Who raised the event</param>
        /// <param name="args">What arguments were passed</param>
        private static void ValidationHandler(object sender, ValidationEventArgs args)
        {
            xmlParseErrorCount++;
            if (args.Exception != null)
            {
                Logger.Log(ErrorLevel.Information, "***XML Validation error\tMessage: " + args.Message + "at " + args.Exception.LineNumber + "," + args.Exception.LinePosition);
            }
            else
            {
                Logger.Log(ErrorLevel.Information, "***XML Validation error\tMessage: " + args.Message);
            }
        }
    }
}
